#pragma once

#include <armadillo>

using arma::mat;
using arma::imat;
using arma::vec2;
using arma::vec3;
using arma::ivec3;
using arma::ivec4;

#ifdef GRAPHENETOOLS_EXPORTS
#ifndef GRAPHENETOOLS_DLL_API
#define GRAPHENETOOLS_DLL_API __declspec(dllexport)
#endif
#else
#ifndef GRAPHENETOOLS_DLL_API
#define GRAPHENETOOLS_DLL_API __declspec(dllimport)
#endif
#endif

// This object declares a carbon atom in a sheet of graphene. 
// Note that atoms cannot be moved only erased or replaced. This library has 
// not been created with any kind of non-static atom considerations.
class GRAPHENETOOLS_DLL_API Atom
{
public:
	// Enum that defines wiether the atom resides in the A or B sublattice.
	enum lattice {
		A = 0,	// Enum that defines the atom resides in the A sublattice.
		B = 1	// Enum that defines the atom resides in the B sublattice.
	};

	// Enum that defines wiether the atom is floating, regular, or dimer.
	enum type {
		floating, // Enum that defines the atom is floating (no neighbours - default).
		regular, // Enum that defines the atom is regular (nondimer).
		dimer // Enum that defines the atom is dimer (has an atom directly above or below - shifts the energy).
	};

private:
	ivec3 pos;		// This container holds the atoms position in the sublattice.
	lattice sublatt;// This container holds the atoms repective sublattice.
	type atomtype;	// This container holds the atoms type, see Atom::type.

public:
	Atom();																	// Default constructor that returns a floating atom at 0,0,0 in the A sublattice.
	Atom(const long &iv, const long &jv, const long &hv, const long &lv);	// Overload constructor that returns a floating atom at i,j,h in the sublattice l.
	Atom(const ivec4 &v);													// Overload constructor that returns a floating atom at v1,v2,v3 in the sublattice v4.
	
	const ivec3 &position() const;		// Getter function that returns the position of the atom in the respective sublattice.
	const lattice &sublattice() const;	// Getter function that returns the respective sublattice.
	ivec4 toIVec4() const;		// Getter function that returns the position and the respective sublattice of the atom in a 4D vector.
	
	long i() const;	// Convenience getter function that returns the first coordinate of position().
	long j() const;	// Convenience getter function that returns the second coordinate of position().
	long h() const;	// Convenience getter function that returns the third coordinate of position().
	long l() const;	// Convenience getter function that returns the sublattice as a long type (0 is A and 1 is B).
	
	type getType() const;			// Getter function the returns the atoms type.
	void setType(const type &t);	// Setter function the sets the atoms type (when neihbours are found the type can be set accordingly).

	bool isDimer() const;
	
	vec3 xyz() const;	// Getter function the transforms the atoms position in lattice coordinates to x,y,z coordinates, cc-bonds are parallel to y-direction.
	vec2 xy() const;	// Getter function the transforms the atoms position in lattice coordinates to x,y coordinates, cc-bonds are parallel to y-direction.
	double x() const;	// Getter function the transforms the atoms position in lattice coordinates to the x coordinate, cc-bonds are parallel to y-direction.
	double y() const;	// Getter function the transforms the atoms position in lattice coordinates to the y coordinate, cc-bonds are parallel to y-direction.
	double z() const;	// Getter function the transforms the atoms position in lattice coordinates to the z coordinate, cc-bonds are parallel to y-direction.
	
	static ivec4 difference(const Atom &a, const Atom &n); // Static evaluation function to find the relative distance between two atoms, used for bond determination.
	static vec3 changeBasis(const ivec4 &v);	// Static helper function.
	static mat changeBasis(const imat &m);	// Static helper function.
	static mat basisChangeMat();// Convenience function initiate the basis change matrix in toXyz().

	typedef std::vector<Atom> list; // Convenience typedef.
	
	class sorter;	// A pre-declaration of the sorting function object Atom::sorter.
	class filter;	// A pre-declaration of the filering function object Atom::filter.

	class reference;// A pre-declared class for referencing atoms in a list (with additional offsets and index if supplied).
};

#include "atomalgorithms.h"
#include "atomreference.h"